#ifndef _API_H_
#define _API_H_

#include "StdAfx.h" //This is for SNAP

#define C 5000

/* 
NOTE: 
You discover nodes by using the command getTeleportNode, getFollowees and get Followers. 
You cannot call getFollowees(i) if node i has not been discovered yet.

If we call the query that will exceed cost limit, the API will return as much data as possible or nonsensical value.
*/

class API
{
public:
    static const int NO_COST_LIMIT = -1;
    PNGraph Discover;

    // Create a query interface for random forest fire graph
    API(int nNode, double forwardBurningProb = 0.35, double backwardBurningProb = 0.32) :
        Discover(TNGraph::New()), total_cost(0), cost_limit(NO_COST_LIMIT) {
        PNGraph G = TSnap::GenForestFire(nNode,forwardBurningProb,backwardBurningProb);
        Graph = TSnap::ConvertGraph<PNEGraph>(G);
    }

    // Create a query interface for random graph with specified
    // number of nodes and edges.
    API(int nNode, int nEdge) : Discover(TNGraph::New()), total_cost(0), cost_limit(NO_COST_LIMIT) {
        PNGraph G = TSnap::GenRndGnm<PNGraph>(nNode,nEdge);
        Graph = TSnap::ConvertGraph<PNEGraph>(G);
    }

    // Create a query interface for the specified graph.
    API(PNEGraph G) : Graph(G), Discover(TNGraph::New()), total_cost(0), cost_limit(NO_COST_LIMIT) {}

    // Return the number of nodes and edges found.
    TIntPr evaluate() { return TIntPr(Discover->GetNodes(), Discover->GetEdges()); }

    int getTotalCost() {return total_cost;}

    void setCostLimit(int costLimit) {cost_limit = costLimit;}

    void enableCache() {cache = true;}
    void disableCache() {cache = false;}
    // BASE QUERY METHODS /////////////////////////////////////////////////////////

    /*
	Return a random seed to start crawling from. This could be drawn from a uniform distribution, but in reality when we are crawling twitter, 
	we can only pick random nodes by sampling from the twitter stream. It is highly likely that we will pick nodes with a lot of activity and 
	thus we might need to have different weights for different nodes.
    */
    int getTeleportNode();

    /*
	If the node has more than C followers, return C followers of the node starting from index. 
	Otherwise, return all the followers of the node. If the index is not specified, it is set to zero.
    */
    TVec<TInt> getFollowers(int NId, int index=0);

    /*
	If the node has more than C followees, return C followees of the node starting from 
	index. Otherwise, return all the followees of the node. If the index is not specified,
	it is set to zero. This corresponds to GET friend request in twitter API.
    */
    TVec<TInt> getFollowees(int NId, int index=0);
    
    /*
	Return the number of followers (in-degree) and followees (out-degree) of a node. Instead of getting the 
	neighbors of a node in batches of C, we might choose to get its degree instead 
	to check first if it is worth exploring or not.
    */
    TIntPr getDegree(int NId);

    // SIMPLIFIED QUERY ROUTINES /////////////////////////////////////////////////
    // These methods could cost more than 1 per call.
    TVec<TInt> getAllFollowers(int NId);
    TVec<TInt> getAllFollowees(int NId);

private:
    bool cache;
    int total_cost;
    int cost_limit;
    PNEGraph Graph;
    THashSet<TInt> asked[2];
};


#define RAND_MAX30  ((RAND_MAX<<15)|RAND_MAX)
inline int rand30(){ return (rand()<<15) | rand(); }

#endif
